package com.snailct.bpp.commons.utils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Hashtable;
import java.util.regex.Pattern;

/**
 * Created by huangxa on 2016/5/24.
 */
public abstract class ReflectUtil {
    private static final Log logger = LogFactory.getLog(ReflectUtil.class);
    public static Object invoke(Object target,String methodName,Object[] args){
        boolean isEmpty = false;
        for(Object arg:args){
            if(arg==null){
                isEmpty = true;
            }
        }
        if(isEmpty)
            args =null;
        Class<?> clazz = target.getClass();
        Method method = findMethod(clazz,methodName,args);
        method.setAccessible(true);
        try {
            if(isEmpty){
                return method.invoke(target);
            }
            return method.invoke(target,args);
        } catch (Exception e) {
            throw new RuntimeException("couldn't invoke "+methodName+" on "+target, e);
        }

    }
    private static Method findMethod(Class<? extends Object> clazz,String methodName,Object[] args){
        for(Method method : clazz.getDeclaredMethods()){
            if(method.getName().equals(methodName)&&matches(method.getParameterTypes(),args)){
                return method;
            }
        }

        Class<?> supperClass = clazz.getSuperclass();
        if(supperClass!=null){
            return findMethod(supperClass,methodName,args);
        }
        return null;
    }
    private static boolean matches(Class< ? >[] parameterTypes, Object[] args) {
        if(parameterTypes==null||parameterTypes.length==0){
            return (args==null||args.length==0);
        }
        if(args==null||parameterTypes.length!=args.length){
            return false;

        }
        for(int i=0;i<parameterTypes.length;i++){
            if(args[i]!=null&&!parameterTypes[i].isAssignableFrom(args[i].getClass())){
                return false;
            }
        }
        return true;
    }

    /**
     *
     * @desc 调用set方法
     */
    public static boolean setMethodValue(Object obj,String property,Object args) {
        Hashtable<String, Method> setMethods = new Hashtable<String, Method>();
        Class cls = obj.getClass();
        Method[] methods = cls.getMethods();
        for(Method method : methods){
            if(!method.getName().startsWith("set")) continue;
            setMethods.put(method.getName().substring(3).toLowerCase(),method);
        }
        String ss = "set(\\w+)";
        Pattern setM = Pattern.compile(ss);
        Method m = setMethods.get(property.toLowerCase());
        if (m != null) {
            try {
                if(m.getParameterTypes()[0].isAssignableFrom(Integer.class)){
                    args = Integer.parseInt(args.toString());
                }else if(m.getParameterTypes()[0].isAssignableFrom(Annotation.class)){

                }
                // 调用目标类的setter函数
                m.invoke(obj, args);
                return true;
            } catch (Exception ex) {
                logger.error("invoke method ["+m.getName()+"] failure!",ex);
                return false;
            }
        }
        return false;
    }
}
